/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package FEMSolver;

import BounderyPack.Boundery;
import BounderyPack.BounderyNodePair;
import BounderyPack.DBoundery;
import BounderyPack.DirihletPair;
import FEMShapeFunctions.FEMShapeFunction1;
import HashMatrix2.HashMatrix2;
import HashMatrix2.LUFactorization;
import Integration.GaussQuadrature;
import Integration.IFunction2D;
import MathLib.triangulation.SaveStructures.Node;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mark_o
 */
public class MPI {
    protected ArrayList<Boundery> NodeList;
    public OutputStream outPath;
    DirihletPair [] mas;
    HashMatrix2 A;
    GaussQuadrature gau = new GaussQuadrature(50);
    double[] b;
    double eps=0.001;
    double H = 5.0;

    public MPI(ArrayList<Boundery> NodeList, OutputStream outPath, DirihletPair[] mas, HashMatrix2 A, double[] b) {
        this.NodeList = NodeList;
        this.outPath = outPath;
        this.mas = mas;
        this.A = A;
        this.b = b;
    }



    private boolean check(double[] prev, double[] next){
        boolean key = true;
        for(int i=0;i<prev.length;i++){
            if(Math.abs(prev[i]-next[i])>eps){
                key = false;
                System.out.print("перевірка:\t");
                System.out.println(i+"\t"+Math.abs(prev[i]-next[i]));
                break;
            }
        }
        return key;
    }

    public void calc(){
        // перше наближення
        LUFactorization lu = new LUFactorization(A);
        double[] u0 = lu.calculate(b);

        while (true) {
            double[] u1 = new double[u0.length];
            double[] uTmp = new double[u0.length];
            for (int i = 0; i < uTmp.length; i++) {
                ArrayList<Double> valList = A.getJRowValues(i);
                ArrayList<Integer> posList = A.getJRowIndex(i);
                double sum1 = 0.0;
                for (int j = 0; j < posList.size(); j++) {
                    sum1+=valList.get(j)*u0[posList.get(j)];
                }
                u1[i]=sum1+u0[i]+P(i, u0[0])/eps-b[i];
            }
            if (check(u0, u1)) {
                u0=u1;
                break;
            }
            u0=u1;
        }
        System.out.println("розвязок\n===================================================================");
        //for(int i=0;i<b.length;i++){
        //    System.out.println((u0[i]));
        //}

        //print result to file

        PrintWriter pw =  null;
        try {
            pw = new PrintWriter(new BufferedOutputStream((outPath)));
            pw.println(u0.length + mas.length);
        if(mas.length>0){
            int j;
            for (j = 0; j < mas[0].getNodeNumber(); j++) {
                pw.println(u0[j]);
            }

            for(int i=0; i<mas.length-1; i++){
                int k=0;
                pw.println(mas[i].getValue());
                while(mas[i+1].getNodeNumber() - mas[i].getNodeNumber()-k!=1){
                    pw.println(u0[j]);
                    j++;
                    k++;
                }
            }

            pw.println(mas[mas.length-1].getValue());

            for (int i = j; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }else{
            for (int i = 0; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }

        } catch (Exception ex) {
            Logger.getLogger(MyPenaltyIteration.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            pw.close();
        }







    }

    private double P(int pos,final double d) {
        double res = 0.0;
        for (int i = 0; i < NodeList.size(); i++) {
                Boundery bound = NodeList.get(i);
                for (int j = 0; j < bound.getNodeList().size(); j++) {
                    final BounderyNodePair pair = bound.getNodeList().get(j);

                    //final double val = Ljambda[pair.getA().Number]*u0[pair.getA().Number];
                    if(pair.getA().Number==pos){
                        IFunction2D f = new IFunction2D() {
                            FEMShapeFunction1 func = new FEMShapeFunction1(pair.getA(), pair.getB(), new Node(pair.getA().x+1, pair.getA().y+pair.getB().y, true, -1));
                            public double calculate(double x, double y) {
                                func.setNodeNum(1);
                                return Math.max(H-d,0)*func.calculate(x, y);
                            }

                            public double calculateDerivatyX(double x, double y) {
                                throw new UnsupportedOperationException("Not supported yet.");
                            }

                            public double calculateDerivatyY(double x, double y) {
                                throw new UnsupportedOperationException("Not supported yet.");
                            }
                        };
                        res+=gau.GaussOnGamma(pair.getA(), pair.getB(), f);
                    }

                    if(pair.getB().Number==pos){
                        IFunction2D f = new IFunction2D() {
                            FEMShapeFunction1 func = new FEMShapeFunction1(pair.getA(), pair.getB(), new Node(pair.getA().x+1, pair.getA().y+pair.getB().y, true, -1));
                            public double calculate(double x, double y) {
                                func.setNodeNum(2);
                                return Math.max(H-d,0)*func.calculate(x, y);
                            }

                            public double calculateDerivatyX(double x, double y) {
                                throw new UnsupportedOperationException("Not supported yet.");
                            }

                            public double calculateDerivatyY(double x, double y) {
                                throw new UnsupportedOperationException("Not supported yet.");
                            }
                        };
                        res+=gau.GaussOnGamma(pair.getA(), pair.getB(), f);
                    }
                }
            }
        return res;
    }
}
